package conn

import (
	"bufio"
	"fmt"
	"frp/src/frp/utils/log"
	"io"
	"net"
	"sync"
)

type Listener struct {
	addr      net.Addr
	l         *net.TCPListener
	conns     chan *Conn
	closeFlag bool
}

// tcp监听
func Listen(bindAddr string, bindPort int64) (l *Listener, err error) {
	tcpAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", bindAddr, bindPort))
	if err != nil {
		return
	}

	// 创建一个监听服务
	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return
	}

	l = &Listener{
		addr:      listener.Addr(),
		l:         listener,
		conns:     make(chan *Conn),
		closeFlag: false,
	}

	// 该函数持续接受新tcp连接加入conns队列
	go func() {
		for {
			// 接受新tcp链接
			conn, err := l.l.AcceptTCP()
			if err != nil {
				log.Error("accepting TCP error, %v", err)
				if l.closeFlag {
					return
				}
				continue
			}

			c := &Conn{
				TcpConn:   conn,
				closeFlag: false,
			}
			c.Reader = bufio.NewReader(c.TcpConn)
			l.conns <- c
		}
	}()

	return
}

// 读取连接
func (l *Listener) GetConn() (conn *Conn, err error) {
	var ok bool
	conn, ok = <-l.conns
	if !ok {
		return conn, fmt.Errorf("channel close")
	}

	return conn, nil
}

func (l *Listener) Close() {
	if l.l != nil && !l.closeFlag {
		l.closeFlag = true
		l.l.Close()
		close(l.conns)
	}
}

type Conn struct {
	TcpConn   *net.TCPConn
	Reader    *bufio.Reader
	closeFlag bool
}

// 创建tcp连接 并返回连接句柄
// host string tcp连接地址
// port integer tcp连接端口
func ConnectServer(host string, port int64) (c *Conn, err error) {
	c = &Conn{}

	// return an address of TCP end point
	serverAddr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", host, port))
	if err != nil {
		return
	}

	// create a TCP connection to the server address
	conn, err := net.DialTCP("tcp", nil, serverAddr)
	if err != nil {
		return
	}

	c.TcpConn = conn
	c.Reader = bufio.NewReader(c.TcpConn)
	c.closeFlag = false
	return
}

// 获取remote_addr
func (c *Conn) GetRemoteAddr() (addr string) {
	return c.TcpConn.RemoteAddr().String()
}

// 获取local_addr
func (c *Conn) GetLocalAddr() (addr string) {
	return c.TcpConn.LocalAddr().String()
}

// 读取
func (c *Conn) ReadLine() (buff string, err error) {
	buff, err = c.Reader.ReadString('\n')
	if err == io.EOF {
		c.closeFlag = true
	}
	return
}

// 发送
func (c *Conn) Write(content string) (err error) {
	_, err = c.TcpConn.Write([]byte(content))

	return
}

// 关闭连接
func (c *Conn) Close() {
	if c.TcpConn != nil && !c.closeFlag {
		c.closeFlag = true
		c.TcpConn.Close()
	}
}

func (c *Conn) IsClose() bool {
	return c.closeFlag
}

// will block until connection close
func Join(c1, c2 *Conn) {
	var wait sync.WaitGroup

	// 将一个连接的数据复制到另一个连接
	pipe := func(to, form *Conn) {
		defer to.Close()
		defer form.Close()
		defer wait.Done()

		var err error
		_, err = io.Copy(to.TcpConn, form.TcpConn)
		if err != nil {
			log.Warn("join conns error, %v", err)
		}
	}

	wait.Add(2)
	go pipe(c1, c2)
	go pipe(c2, c1)
	wait.Wait()
}
